package com.atguigu.paymentdemo.controller;


import com.atguigu.paymentdemo.service.WxPayService;

import com.atguigu.paymentdemo.uitl.HttpUtils;
import com.atguigu.paymentdemo.uitl.WechatPayRequest2Validator;
import com.atguigu.paymentdemo.vo.R;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.google.gson.Gson;

@CrossOrigin//开放前端跨域
@Api(tags = "支付管理")
@Slf4j
@RestController
@RequestMapping("/api/wx-pay")
public class WxPayController {


    @Resource
    WxPayService wxPayService;
    @Resource
    Gson gson;
    @Resource
    Verifier verifier;

    @Resource
    WechatPayRequest2Validator wpr2v;

    final String ServerExceptionMessage = "服务器异常";
    final String SignVerFailedMessage = "验签失败";
    final String SuccessMessage = "成功";

    @ApiOperation("调用下单API，生成支付二维码")
    @PostMapping("native/{productId}")
    public R nativePay(@PathVariable(value = "productId") Long productId) throws Exception {
        log.info("发起支付请求");

        //通过订单实体调用 下单API，返回二维码
        Map map = wxPayService.nativePay(productId,1L);

        //返回二维码和订单号
        R r = R.ok();
        r.setData(map);
        return r;
    }

    @ApiOperation("支付通知")
    //回调URL：该链接是通过基础下单接口中的请求参数“notify_url”来设置的，
    // 要求必须为https地址。
    @PostMapping("native/notify")
    public String nativePayNotify(HttpServletRequest request, HttpServletResponse response){
        Map<String, String> result = new HashMap<>();//应答对象
        try{
            //通知信息读取
            String requestBody = HttpUtils.readData(request);

            Map<String,Object> requestBodyMap = gson.fromJson(requestBody, HashMap.class);

            //验签
            if(wpr2v.validate(request,requestBody)){
                log.info(String.valueOf(requestBodyMap));
                log.info("支付通知id:"+requestBodyMap.get("id"));
                log.info("支付通知主体:"+requestBodyMap.get("resource"));

                //订单处理
                wxPayService.processOrder((Map<String,String>) requestBodyMap.get("resource"));

                //应答超时
                //设置响应超时，可以接收到微信支付的重复的支付结果通知。
                //通知重复，数据库会记录多余的支付日志
                TimeUnit.SECONDS.sleep(10);
            }else{
                putErrorMessage(response,result,SignVerFailedMessage);
                return gson.toJson(result);
            }

        }catch(Exception e){
            //服务器异常 接收失败：HTTP应答状态码需返回5XX或4XX，同时需返回应答报文
            putErrorMessage(response,result,ServerExceptionMessage);
            return gson.toJson(result);
        }

        //接收成功：HTTP应答状态码需返回200或204，无需返回应答报文。
        response.setStatus(200);
        return  null;
    }



    @PostMapping("/cancel/{orderNo}")
    public R cancel(@PathVariable String orderNo) throws IOException {

        wxPayService.cancelOrder(orderNo);
        return R.ok().setMessage("订单已取消");

    }

    @PostMapping("/refunds/{orderNo}/{reason}")
    public R refund(@PathVariable String orderNo, @PathVariable String reason) throws IOException {
        log.info("申请退款");
        wxPayService.orderRefund(orderNo,reason);
        return R.ok();
    }

    @ApiOperation("退款通知")
    //回调URL：该链接是通过基础下单接口中的请求参数“notify_url”来设置的，
    // 要求必须为https地址。
    @PostMapping("refunds/notify")
    public String refundNotify(HttpServletRequest request, HttpServletResponse response){
        log.info("退款回调通知到达");
        Map<String, String> result = new HashMap<>();//应答对象
        try{
            //通知信息读取
            String requestBody = HttpUtils.readData(request);

            Map<String,Object> requestBodyMap = gson.fromJson(requestBody, HashMap.class);

            //验签
            if(wpr2v.validate(request,requestBody)){
                log.info(String.valueOf(requestBodyMap));
                log.info("退款通知id:"+requestBodyMap.get("id"));
                log.info("退款通知主体:"+requestBodyMap.get("resource"));

                //订单处理
                wxPayService.processRefundOrder((Map<String,String>) requestBodyMap.get("resource"));

            }else{
                putErrorMessage(response,result,SignVerFailedMessage);
                return gson.toJson(result);
            }

        }catch(Exception e){
            //服务器异常 接收失败：HTTP应答状态码需返回5XX或4XX，同时需返回应答报文
            putErrorMessage(response,result,ServerExceptionMessage);
            return gson.toJson(result);
        }

        //接收成功：HTTP应答状态码需返回200或204，无需返回应答报文。
        putSuccessMessage(response,result,SuccessMessage);
        return gson.toJson(result);
    }

    public void putErrorMessage(HttpServletResponse response,Map<String, String> res,String message){
        //服务器异常 接收失败：HTTP应答状态码需返回5XX或4XX，同时需返回应答报文
        res.put("code","FAIL");
        res.put("message",message);
        response.setStatus(404);
    }

    public void putSuccessMessage(HttpServletResponse response,Map<String, String> res,String message){
        //服务器异常 接收失败：HTTP应答状态码需返回5XX或4XX，同时需返回应答报文
        res.put("code","SUCCESS");
        res.put("message",message);
        response.setStatus(200);
    }


}
